using System;
using System.Collections;
using System.Collections.Specialized;

namespace SharpMud.MudLib.SAMPLE.Net
{
	public class SessionStateStack : ISessionStateStack
	{
		#region Private Variables
		private System.Collections.GenericStack<ISessionState>	_Stack;
		private ISessionState				_ParentState;
		private string						_StateID;
		private Net.TelnetPlayerSession		_Session;
		private System.Collections.GenericQueue<byte> _OutgoingDataQueue;
		#endregion

		#region Constructors
		private SessionStateStack()
		{
			_Stack = new GenericStack<ISessionState>();
            _OutgoingDataQueue = new GenericQueue<byte>();
		}
		public SessionStateStack(string stateID)
			:this(null,stateID)
		{
		}
		public SessionStateStack(ISessionState parentState, string stateID)
			:this()
		{
			_ParentState = parentState;
			_StateID = stateID;
		}
		#endregion
		
		#region IStack Members

		public void Clear()
		{
			_Stack.Clear();
		}

		object IStack.Pop()
		{
			return _Stack.Pop();
		}

		public ISessionState Pop()
		{
			return (ISessionState)_Stack.Pop();
		}

		void IStack.Push(object value)
		{
			_Stack.Push((ISessionState)value);
		}

		public void Push(ISessionState value)
		{
			Push(value,true);
		}

		public void Push(ISessionState value, bool autoInitialize)
		{
			if(autoInitialize && value.ParentState==null)
			{
				value.Initialize(this,_Session);
			}
			_Stack.Push(value);
		}

		object IStack.Peek()
		{
			return _Stack.Peek();
		}

		public ISessionState Peek()
		{
			if(_Stack.Count<=0)
				return null;
			else
				return (ISessionState)_Stack.Peek();
		}

		#endregion

		#region ICollection Members

		public bool IsSynchronized
		{
			get
			{
				return _Stack.IsSynchronized;
			}
		}

		public int Count
		{
			get
			{
				return _Stack.Count;
			}
		}

		public void CopyTo(Array array, int index)
		{
			_Stack.CopyTo(array,index);
		}

		public object SyncRoot
		{
			get
			{
				return _Stack.SyncRoot;
			}
		}

		#endregion

		#region IEnumerable Members

		public System.Collections.IEnumerator GetEnumerator()
		{
			return _Stack.GetEnumerator();
		}

		#endregion

		#region ISessionState Members

		public void	Initialize(Net.TelnetPlayerSession session)
		{
			_Session = session;
		}
		public void	Initialize(ISessionState parentState, Net.TelnetPlayerSession session)
		{
			this._ParentState = parentState;
			this._Session = session;
		}

		public ISessionState ParentState
		{
			get
			{
				return this._ParentState;
			}
		}

		public void Pulse()
		{
			ClearInactive();
			if(this.Peek()!=null)
			{this.Peek().Pulse();}
			GrabOutgoingData();
			SendOutgoingData();
		}

		private void GrabOutgoingData()
		{
			if(this.Peek()==null) return;
			while(this.Peek().OutgoingDataQueue.Count>0)
			{
				this.OutgoingDataQueue.Enqueue(this.Peek().OutgoingDataQueue.Dequeue());
			}
		}

		private void SendOutgoingData()
		{
			if(this.Peek()==null) return;
			if(this.OutgoingDataQueue.Count>0)
			{
				byte[] bytes = this.OutgoingDataQueue.ToArray();
				this.OutgoingDataQueue.Clear();
				this._Session.Stream.Write(bytes,0,bytes.Length);
			}
		}

		private void ClearInactive()
		{
			while(this.Count>0)
			{
				if(this.Peek().StillActive==false)
				{
					this.Peek().Dispose();
					this.Pop();		
				}
				else
				{
					break;
				}
			}
		}

		public System.Collections.GenericQueue<byte> OutgoingDataQueue
		{
			get
			{
				return this._OutgoingDataQueue;
			}
		}

		public string StateID
		{
			get
			{
				return this._StateID;
			}
		}

		public bool StillActive
		{
			get
			{
				if(this.Count>0)
					return true;
				else
					return false;
			}
		}

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
			while(this.Count>0)
			{
				this.Pop().Dispose();			
			}
		}

		#endregion

        #region IStack Members


        bool IStack.Contains(object value)
        {
            return ((IStack)(_Stack)).Contains(value);
        }

        object[] IStack.Peek(int count)
        {
            return ((IStack)(_Stack)).Peek(count);
        }

        object[] IStack.Pop(int count)
        {
            return ((IStack)(_Stack)).Pop(count);
        }

        object[] IStack.ToArray()
        {
            return ((IStack)(_Stack)).ToArray();
        }

        #endregion

        #region ISessionState Members


        IQueue<byte> ISessionState.OutgoingDataQueue
        {
            get { return this._OutgoingDataQueue; }
        }

        #endregion
    }
}
